package com.nwpu.coursesupport.service.imple;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.nwpu.coursesupport.criteria.BatchClassStudentSearchCriteria;
import com.nwpu.coursesupport.criteria.ClassSearchCriteria;
import com.nwpu.coursesupport.criteria.ClassStudentSearchCriteria;
import com.nwpu.coursesupport.criteria.ClassViewSearchCriteria;
import com.nwpu.coursesupport.criteria.StudentSearchCriteria;
import com.nwpu.coursesupport.entity.Class;
import com.nwpu.coursesupport.entity.ClassStudent;
import com.nwpu.coursesupport.entity.Resource;
import com.nwpu.coursesupport.entity.Student;
import com.nwpu.coursesupport.entity.bean.JSONResult;
import com.nwpu.coursesupport.enumeration.ClassType;
import com.nwpu.coursesupport.enumeration.Gender;
import com.nwpu.coursesupport.enumeration.RoleType;
import com.nwpu.coursesupport.enumeration.Status;
import com.nwpu.coursesupport.exception.StudentBatchAddException;
import com.nwpu.coursesupport.mapper.ClassMapper;
import com.nwpu.coursesupport.mapper.ClassStudentMapper;
import com.nwpu.coursesupport.mapper.ResourceMapper;
import com.nwpu.coursesupport.mapper.StudentMapper;
import com.nwpu.coursesupport.pagination.PageBounds;
import com.nwpu.coursesupport.service.ClassStudentService;
import com.nwpu.coursesupport.service.param.ClassStudentServiceParam;
import com.nwpu.coursesupport.service.param.ClassStudentServiceParam.CreateClassItem;
import com.nwpu.coursesupport.service.param.ClassStudentServiceParam.SearchViewParam;
import com.nwpu.coursesupport.service.param.IDListParam;
import com.nwpu.coursesupport.service.param.IDParam;
import com.nwpu.coursesupport.tool.EncryptionUtil;
import com.nwpu.coursesupport.tool.ExcelReader;
import com.nwpu.coursesupport.tool.ServiceUtil;
import com.nwpu.coursesupport.tool.UpdateUtil;
import com.nwpu.coursesupport.view.ClassView;
import com.nwpu.coursesupport.view.StudentSearchView;

@Service("csService")
public class ClassStudentServiceimple extends UserService implements ClassStudentService {
	@Autowired
	private ClassStudentMapper classStudentMapper;
	@Autowired
	private ClassMapper classMapper;
	@Autowired
	private StudentMapper studentMapper;
	@Autowired
	private ResourceMapper resourceMapper ;
	
	protected static Logger logger = LoggerFactory.getLogger(ClassStudentServiceimple.class);
	
	public JSONResult detail(IDParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();
		if (p == null || p.getId() <= 0) {
			logger.error("参数有误");
			rst.fail("参数有误");
			return rst;
		}

		ClassStudent classStudent = this.classStudentMapper.findById(p.getId());

		rst.addData("classStudent", classStudent);
		rst.success();
		return rst;
	}

	@Transactional
	public JSONResult batchCreateSmallClass(ClassStudentServiceParam.BatchCreateParam p) throws StudentBatchAddException {
		JSONResult rst = new JSONResult();
		rst.fail();
		if (p == null || p.getStudentId() == null || p.getStudentId().size() <= 0) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}
		int id = (int) getSession().getAttribute("id");
		String name=(String) getSession().getAttribute("name");
		RoleType roleType = (RoleType) getSession().getAttribute("roleType");
		
		
		Class c = this.classMapper.findById(p.getClassId());
		if (c == null) {
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
		
		if(c.getClassType()==ClassType.CLASS){
			logger.error("班级类型有误");
			return rst.fail("班级类型有误");
		}

		//添加到小班的学生必须已经在大班中了
		BatchClassStudentSearchCriteria sc = new BatchClassStudentSearchCriteria();
		sc.setClassId(c.getFid());
		sc.setStudentIds(p.getStudentId());
		List<Integer> rs=this.classStudentMapper.findByIds(sc);//输入对应班级的大班学生
		if(rs==null||rs.size()<=0){
			logger.error("相关同学已已加入到相关班级");
			return rst.fail("相关同学已已加入到相关班级");
		}
		p.setStudentId(rs);
		
		//去掉已经在当前班级中的学生
		sc = new BatchClassStudentSearchCriteria();
		sc.setClassId(p.getClassId());
		sc.setStudentIds(p.getStudentId());
		List<Integer> ids = this.classStudentMapper.findByIds(sc);
		p.getStudentId().removeAll(ids);//已经加入该班级的
		
		//管理班级中每一个学生只能添加一次
		if(c.getClassType()==ClassType.MANAGETEAM){
			sc = new BatchClassStudentSearchCriteria();
			sc.setFid(c.getFid());
			sc.setClassType(ClassType.MANAGETEAM);
			ids=this.classStudentMapper.findByIds(sc);
			p.getStudentId().removeAll(ids);//已经加入同一大班其他行政班级
		}
		
		List<ClassStudent> list = new ArrayList<ClassStudent>();
		ClassStudent cs = null;
		Date date = new Date();

		for (Integer item : p.getStudentId()) {
			cs = new ClassStudent();
			cs.setStudentId(item);
			cs.setCourseId(c.getCourseId());
			cs.setClassId(c.getId());
			cs.setJoinDate(date);
			cs.setUpdateDate(date);

			cs.setUpdateOperatorId(id);
			cs.setUpdateOperatorName(name);
			cs.setRoleType(roleType);
			list.add(cs);
		}
		if (list.size() <= 0) {
			logger.error("list.size()<=0");
			return rst.success();
		}
		
		if (this.classStudentMapper.batchSave(list) != list.size()) {
			logger.error("批量添加学生失败,并抛出异常StudentBatchAddException");
			throw new StudentBatchAddException("批量添加学生失败");
		}
		rst.success();
		rst.setMessage("成功添加"+list.size()+"个学生到相关班级");
		return rst;
	}

	@Transactional
	public JSONResult batchCreateClass(ClassStudentServiceParam.BatchCreateClassParam p)throws StudentBatchAddException{
		JSONResult rst = new JSONResult();
		rst.fail();
		if (p == null || p.getList() == null || p.getList().size() <= 0) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}
		
		int id = (int) getSession().getAttribute("id");
		String name=(String) getSession().getAttribute("name");
		RoleType roleType = (RoleType) getSession().getAttribute("roleType");
		
		Class c = this.classMapper.findById(p.getClassId());
		if (c == null) {
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
		if(c.getClassType()!=ClassType.CLASS){
			logger.error("添加班级类型有误");
			return rst.fail("添加班级类型有误");
		}
		
		List<String> studentCodes=new ArrayList<String>(p.getList().size());
		p.getList().forEach(item->{
			studentCodes.add(item.getStudentCode());
		});
		
		List<Integer> stuIds=new ArrayList<Integer>();//保存所有的学生id
		
		List<Student> exitStudents=this.studentMapper.findByCodes(studentCodes);//找出存在的学生
		
		List<String> exitCodes=new ArrayList<String>(exitStudents.size());//存在学生的学号
		exitStudents.forEach(item->{
			exitCodes.add(item.getStudentCode());
			stuIds.add(item.getId());
		});
		
		
		List<Student> addStudentList=new ArrayList<Student>();
		Date createDate=new Date();
		p.getList().forEach(item->{
			if(!exitCodes.contains(item.getStudentCode())){
				Student s=new Student();
				s.setStudentCode(item.getStudentCode());
				s.setClassNumber(item.getClassNumber());
				s.setName(item.getName());
				/*set password as studentCode*/
				s.setPassword(EncryptionUtil.Encryption(s.getStudentCode(),s.getStudentCode()));
				s.setIsFirst(Status.YES);
				s.setCreateDate(createDate);
				s.setUpdateDate(createDate);
				/*default male*/
				s.setGender(Gender.MALE);
				s.setPicture(getHeaderImage(Gender.MALE));
				addStudentList.add(s);
			}
		});
		
		if(addStudentList.size()>0){
			if(this.studentMapper.batchSave(addStudentList)!=addStudentList.size()){
				logger.error("批量添加学生失败，并抛出异常：StudentBatchAddException");
				new StudentBatchAddException("批量添加学生失败");
			}
			addStudentList.forEach(item->{
				stuIds.add(item.getId());
			});
		}
		
		//找出这些id中已经加入到该课程的学生
		BatchClassStudentSearchCriteria sc = new BatchClassStudentSearchCriteria();
		sc.setCourseId(c.getCourseId());
		sc.setClassType(ClassType.CLASS);
		sc.setStudentIds(stuIds);
		List<Integer> hasJoineds = this.classStudentMapper.findByIds(sc);
		stuIds.removeAll(hasJoineds);//已经加入了同一课程的其他大班中的学生
		
		//开始往课程中添加学生
		List<ClassStudent> list = new ArrayList<ClassStudent>();
		ClassStudent cs = null;
		Date date = new Date();

		for (Integer item : stuIds) {
			cs = new ClassStudent();
			cs.setStudentId(item);
			cs.setCourseId(c.getCourseId());
			cs.setClassId(c.getId());
			cs.setJoinDate(date);
			cs.setUpdateDate(date);

			cs.setUpdateOperatorId(id);
			cs.setUpdateOperatorName(name);
			cs.setRoleType(roleType);
			list.add(cs);
		}
		StringBuilder sb=null;
		if (list.size() <= 0) {
			sb=new StringBuilder();
			if(hasJoineds.size()>0){
				sb.append("当前所上传学生中"+hasJoineds.size()+"个学生已加入到该课程,");
			}
			sb.append("成功新添加"+list.size()+"个学生到相关班级");
			logger.error("list.size() <= 0");
			rst.setMessage(sb.toString());
			return rst.success();
		}
		if (this.classStudentMapper.batchSave(list) != list.size()) {
			logger.error("批量添加学生失败,并抛出异常StudentBatchAddException");
			throw new StudentBatchAddException("批量添加学生失败");
		}
		
		sb=new StringBuilder();
		if(hasJoineds.size()>0){
			sb.append("当前所上传学生中"+hasJoineds.size()+"个学生已加入到该课程,");
		}
		sb.append("成功新添加"+list.size()+"个学生到相关班级");
		rst.setMessage(sb.toString());
		rst.success();
		return rst;
	}
	
	public JSONResult parseByExcel(ClassStudentServiceParam.CreateByExcelParam p){
		JSONResult rst = new JSONResult();
		rst.fail();
		//StringBuilder sb=new StringBuilder();
		//sb.append("");
		if(p==null||p.getClassId()<=0){
			logger.error("参数出错");
			return rst.fail("参数出错");
		}
		
		Class  c=this.classMapper.findById(p.getClassId());
		if(c==null){
			logger.error("目标班级不存在");
			return rst.fail("目标班级不存在");
		}
		
		Resource resource=this.resourceMapper.findByKey(p.getKey());
		if(resource==null){
			logger.error("该资源不存在");
			return rst.fail("该资源不存在");
		}
		
		ExcelReader excel=new ExcelReader();
		//excel
		List<List<String>> source=excel.read(resource);
		if(source==null||source.size()<=1){
			logger.error("excel解析失败:"+excel.getErrorInfo());
			return rst.fail("excel解析失败:"+excel.getErrorInfo());
		}
		// 班级  学号   姓名
		//校验Excel格式
		List<String> title=source.get(0);
		if(title.size()<3||!"班级".equals(title.get(0))||!"学号".equals(title.get(1))||!"姓名".equals(title.get(2))){
			logger.error("文档格式不正确，解析学生信息失败");
			return rst.fail("文档格式不正确，解析学生信息失败");
		}
		
		List<CreateClassItem> stus=new ArrayList<CreateClassItem>();
		CreateClassItem s=null;
		for(int i=1;i<source.size();i++){
			List<String> item = source.get(i);
			if(item.size()<3){
			/*	sb.append(item).append("\n");*/
				continue;
			}
			s=new CreateClassItem();
			s.setClassNumber(item.get(0));
			s.setStudentCode(item.get(1));
			s.setName(item.get(2));
			stus.add(s);
		}
		
		if(stus.size()<=0){
			logger.error("Excel解析失败，无法解析学生信息:stus.size()<=0");
			return rst.fail("Excel解析失败，无法解析学生信息");
		}
		
		rst.success();
		rst.addData("list", stus);
		return rst;
	}
	
	
	public JSONResult create(ClassStudentServiceParam.CreateParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();

		if (p == null||p.getClassId()==null) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}

		ClassStudent classStudent = p;

		Class c = this.classMapper.findById(classStudent.getClassId());
		if (c == null) {
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
		if(c.getClassType()!=ClassType.CLASS){
			logger.error("无相关权限");
			return rst.role("无相关权限");
		}
		int id = (int) getSession().getAttribute("id");
		String name=(String) getSession().getAttribute("name");
		RoleType roleType = (RoleType) getSession().getAttribute("roleType");
		if(classStudent.getStudentId()==null){
			logger.error("学生id为空");
			return rst.fail("学生id为空");
		}
		Student st = this.studentMapper.findById(classStudent.getStudentId());
		if (st == null) {
			logger.error("该学生不存在");
			return rst.fail("该学生不存在");
		}
	
		ClassStudentSearchCriteria sc = new ClassStudentSearchCriteria();
		sc.setCourseId(c.getCourseId());
		sc.setStudentId(classStudent.getStudentId());
		List<ClassStudent> list = this.classStudentMapper.find(sc);
		System.out.println(list.size());

		if (list != null && list.size() > 0) {
			logger.error("该学生已加入该课程");
			Class courseClass = this.classMapper.findById(list.get(0).getClassId());		
			if(courseClass == null || courseClass.getName() == null){
				return rst.fail("该学生已加入本课程！但所在班级数据有误，请联系管理员");
			}else {
				return rst.fail("该学生已加入本课程的  "+courseClass.getName()+" 班");
			}
			
		}

		classStudent.setCourseId(c.getCourseId());
		classStudent.setJoinDate(new Date());
		classStudent.setUpdateDate(new Date());
		classStudent.setUpdateOperatorName(name);
		classStudent.setUpdateOperatorId(id);
		classStudent.setRoleType(roleType);
		if (!this.classStudentMapper.save(classStudent)) {
			logger.error("保存失败");
			return rst.fail("保存失败");
		}

		rst.addData("classStudent", classStudent);
		rst.success();
		return rst;
	}

	// 用于添加学生成绩 教师权限
	public JSONResult update(ClassStudentServiceParam.UpdateParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();

		if (p == null || p.getId() <= 0) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}

		ClassStudent classStudent = this.classStudentMapper.findById(p.getId());
		if (classStudent == null || classStudent.getClassId() != p.getClassId()) {
			logger.error("记录不存在或已被删除");
			return rst.fail("记录不存在或已被删除");
		}
		Class c = this.classMapper.findById(p.getClassId());
		if (c == null || c.getClassType() != ClassType.CLASS) {
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
		if (UpdateUtil.setValues(classStudent, p) > 0) {
			int id = (int) getSession().getAttribute("id");
			RoleType roleType = (RoleType) getSession().getAttribute("roleType");
			classStudent.setUpdateOperatorId(id);
			classStudent.setRoleType(roleType);
			classStudent.setUpdateDate(new Date());
			if (!this.classStudentMapper.update(classStudent)) {
				logger.error("保存失败");
				return rst.fail("保存失败");
			}
		}

		rst.addData("classStudent", classStudent);
		rst.success();
		return rst;
	}

	public JSONResult remove(IDParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();

		if (p == null || p.getId() <= 0) {
			logger.error("参数有误");
			rst.fail("参数有误");
			return rst;
		}
		ClassStudent classStudent = this.classStudentMapper.findById(p.getId());
		if (classStudent == null) {
			return rst.fail("记录不存在或已被删除");
		}

		if (!this.classStudentMapper.delete(p.getId())) {
			logger.error("删除失败");
			return rst.fail("删除失败");
		}
		rst.addData("classStudent", classStudent);
		rst.success();
		return rst;
	}

	@Transactional
	public JSONResult removeAll(IDListParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();

		if (p == null || p.getIds() == null || p.getKeyId() == null || p.getIds().isEmpty()) {
			logger.error("参数有误");
			rst.fail("参数有误");
			return rst;
		}

		Class c =this.classMapper.findById(p.getKeyId());
		if(c==null){
			logger.error("该班级不不存在");
			return rst.fail("该班级不不存在");
		}
		this.classStudentMapper.batchDelete(p);
		if(c.getClassType()==ClassType.CLASS){
			ClassSearchCriteria sc=new ClassSearchCriteria();
			sc.setFid(p.getKeyId());
			List<Class> cls=this.classMapper.find(sc);
			for(Class item : cls){
				p.setKeyId(item.getId());
				this.classStudentMapper.batchDelete(p);
			}
		}
		rst.success();
		return rst;
	}

	public JSONResult findStudentByParam(ClassStudentSearchCriteria sc) {
		JSONResult rst = new JSONResult();
		rst.fail();

		if (sc == null || sc.getClassId() == 0) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}

		Class c = this.classMapper.findById(sc.getClassId());
		if (c == null) {
			logger.error("班级不存在");
			return rst.fail("班级不存在");
		}
		
		if (c.getClassType()==ClassType.MANAGETEAM) {//管理班级
			sc.setSonId(sc.getClassId());
			sc.setClassId(c.getFid());
			sc.setClassType(c.getClassType());
		}else if(c.getClassType()==ClassType.TASKTEAM){//任务班级
			sc.setSonId(sc.getClassId());
			sc.setClassId(c.getFid());
			sc.setClassType(null);
		}else{
			sc.setClassType(null);;
		}
		if (sc.getPageNo() <= 0){
			sc.setPageNo(1);
		}
		
		
		int pageSize = 20;
        int totalCount =this.classStudentMapper.countStudentByParam(sc);
        int pageCount = totalCount % pageSize > 0 ? totalCount / pageSize + 1 : totalCount / pageSize;
		if (sc.getPageNo() > pageCount){
			sc.setPageNo(pageCount);
		}
		
		PageBounds page = new PageBounds();
        page.setNumber(sc.getPageNo());
        page.setSize(pageSize);

		List<Student> list = this.classStudentMapper.findStudentByParam(sc,page);

		rst.addData("list", list);
		rst.addData("pageNo", sc.getPageNo());
		rst.addData("allpages", pageCount);
		rst.success();
		return rst;
	}
	
	
	public JSONResult searchListData(ClassStudentSearchCriteria sc) {
		JSONResult rst = new JSONResult();
		rst.fail();
		
		if (sc == null || sc.getKeywords() == null||sc.getClassId()<=0) {
			logger.error("参数有误");
			return rst.fail("参数有误");
		}
		Class c=this.classMapper.findById(sc.getClassId());
		if(c==null){
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
		
		if(c.getClassType()==ClassType.CLASS){
			sc.setSonId(null);
			sc.setClassType(null);
			rst=doClassSearch(sc);
		}else if(c.getClassType()==ClassType.MANAGETEAM){
			sc.setClassId(c.getFid());
			sc.setSonId(c.getId());
			sc.setClassType(c.getClassType());
			rst=doGroupSearch(sc);
		}else{
			sc.setClassId(c.getFid());
			sc.setSonId(c.getId());
			sc.setClassType(null);
			rst=doGroupSearch(sc);
		}

		return rst;
	}
	//班级全局搜索
	private JSONResult doClassSearch(ClassStudentSearchCriteria sc){
		JSONResult rst=new JSONResult();
		rst.fail();
		
		StudentSearchCriteria ssc = new StudentSearchCriteria();
		ssc.setKeywords(sc.getKeywords());
		
		if (sc.getPageNo() <= 0){
			sc.setPageNo(1);
		}
		
		int pageSize = 20;
        int totalCount =this.studentMapper.count(ssc);
        int pageCount = totalCount % pageSize > 0 ? totalCount / pageSize + 1 : totalCount / pageSize;
		if (sc.getPageNo() > pageCount){
			sc.setPageNo(pageCount);
		}
		
		PageBounds page = new PageBounds();
        page.setNumber(sc.getPageNo());
        page.setSize(pageSize);
		
		List<Student> students = this.studentMapper.find(ssc,page);
		
		List<StudentSearchView> searchView = new ArrayList<StudentSearchView>();
		if (sc.getClassId() <= 0) {// 没有课程的参数
			students.forEach(item -> {
				StudentSearchView ssv = new StudentSearchView();
				UpdateUtil.setValues(ssv, item);
				searchView.add(ssv);
			});
			rst.addData("list", searchView);
		}
		ClassStudentSearchCriteria csc = new ClassStudentSearchCriteria();
		csc.setClassId(sc.getClassId());
		List<Student> list = this.classStudentMapper.findStudentByParam(csc);

		students.forEach(item -> {
			StudentSearchView ssv = new StudentSearchView();
			UpdateUtil.setValues(ssv, item);
			searchView.add(ssv);
			if (list.contains(item)) {
				ssv.setHasJoined(1);
			}
		});

		rst.addData("list", searchView);
		
		rst.success();
		return rst;
		
	}
	
	//组内搜索
	private JSONResult doGroupSearch(ClassStudentSearchCriteria sc){
		JSONResult rst=new JSONResult();
		rst.fail();
		
		if (sc.getPageNo() <= 0){
			sc.setPageNo(1);
		}
		
		int pageSize = 20;
        int totalCount =this.classStudentMapper.countStudentByParam(sc);
        int pageCount = totalCount % pageSize > 0 ? totalCount / pageSize + 1 : totalCount / pageSize;
		if (sc.getPageNo() > pageCount){
			sc.setPageNo(pageCount);
		}
		
		PageBounds page = new PageBounds();
        page.setNumber(sc.getPageNo());
        page.setSize(pageSize);

		List<Student> list = this.classStudentMapper.findStudentByParam(sc,page);
		rst.addData("list", list);
		rst.addData("pageNo", sc.getPageNo());
		rst.addData("allpages", pageCount);
		rst.success();
		
		return rst;
	}

	@Override
	public JSONResult listView(SearchViewParam p) {
		JSONResult rst = new JSONResult();
		rst.fail();
		if(p==null||p.getClassId()<=0){
			logger.error("参数出错");
			return rst.fail("参数出错");
		}
		
		if (p.getPageNo() <= 0){
			p.setPageNo(1);
		}
		ClassViewSearchCriteria cvsc=new ClassViewSearchCriteria();
		cvsc.setClassId(p.getClassId());
		ClassView view=this.classMapper.getClassView(cvsc);
		if(view==null){
			logger.error("该班级不存在");
			return rst.fail("该班级不存在");
		}
        view.setTheoryDate(ServiceUtil.DeserializeDate(view.getTheoryDateBytes()));
        view.setLabDate(ServiceUtil.DeserializeDate(view.getLabDateBytes()));
		//if(view.getClassType()!=Clas)
		
		ClassStudentSearchCriteria csc = new ClassStudentSearchCriteria();
		csc.setClassId(p.getClassId());
		
		int pageSize = 20;
        int totalCount =this.classStudentMapper.countStudentByParam(csc);
        int pageCount = totalCount % pageSize > 0 ? totalCount / pageSize + 1 : totalCount / pageSize;
		if (p.getPageNo() > pageCount){
			p.setPageNo(pageCount);
		}
		PageBounds page = new PageBounds();
        page.setNumber(p.getPageNo());
        page.setSize(pageSize);
		
		List<Student> list=this.classStudentMapper.findStudentByParam(csc,page);
		
		rst.success();
		rst.addData("classView", view);
		rst.addData("students", list);
		rst.addData("pageNo",p.getPageNo());
		rst.addData("allpages",pageCount);
		return rst;
	}
	
	 

}
